#ifndef     __ELEVATOR_MOTOR_H
#define     __ELEVATOR_MOTOR_H

#include "../../utils/object.h"
#include "../../utils/nocopyable.h"
#include "../../rtos/event_flags.h"
#include "../../utils/step_motor_acc_ctrl.h"
#include "../../utils/error.h"

namespace driver {

class ElevatorMotor : 
    private utils::NoCopyable,
    public utils::StepMotorAccCtrl<ElevatorMotor, 200, 4, 1200> {

public:
    static constexpr uint32_t FLAG_COMPLETE = 0x01;

    static constexpr uint32_t ADJ_MAX_COUNT = 1000;
    static constexpr uint32_t RESET_TIMEOUT = 50 * 1000;
    static constexpr uint32_t RESET_FREQ = 2000;

    enum class Dir : uint8_t {
        UP = 0,
        DOWN = 1,
        RELEASE = 2,
    };

    ElevatorMotor();
    static bool is_alm();
    inline void notify() { m_flags.set_flags(FLAG_COMPLETE); }
    static void disable_pwm();
    static void set_pwm_freq(uint32_t freq);
    static void enable_pwm(uint32_t base_freq);
    static void enable_pwm_not_irq(uint32_t freq);

    utils::Error async_with_mm(uint16_t mm) {
        return async_run(mm * 400 / 3);
    }
    utils::Error run_with_mm(uint16_t mm) {
        return run(mm * 400 / 3);
    }

    utils::Error async_run(uint16_t position);
    utils::Error wait_for();
    utils::Error run(uint16_t position);
    
private:
    inline void await() { m_flags.wait_any_flags(FLAG_COMPLETE);}
    static void set_dir(Dir dir);
    static utils::Error reset_adj();
    utils::Error reset();

    uint16_t m_position = 0;
    bool m_reset_flag = false;
    rtos::EventFlags m_flags;
};

inline utils::Object<ElevatorMotor> elevatorMotor;

}



#endif
